//生产消费模型
#pragma once


#include<iostream>
#include<queue>
#include<pthread.h>
using namespace std;
const int gmaxcap=5;
template<class T>
class BlockQueue
{

public:
    BlockQueue(const int &maxcap=gmaxcap)
    :_maxcap(gmaxcap)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_pcond,nullptr);
        pthread_cond_init(&_ccond,nullptr);

    }
    void push(const T &in)//向队列放数据  输入型参数：const&
    {
        pthread_mutex_lock(&_mutex);
        //1.判断
        //细节2:充当条件必须是while，不能用if ps:当线程被唤醒时有可能队列还是满的出现异常
        while(is_full())//判断队列是否满了
        {
            //细节1：pthread这个函数第二个参数必须是我们正在使用的互斥锁！
            //a.pthread_cond_wait:该函数，会以原子性方式，将锁释放，并将自己挂起
            //b.该函数在被唤醒返回的时候会重新获取锁
            pthread_cond_wait(&_pcond,&_mutex);//因为生产条件不满足，我们无法进行生产,进行等待
        }
        //2.走到这里一定没有满
        _q.push(in);
        //3.保证阻塞队列一定有数据
        //让消费者进行消费
        pthread_cond_signal(&_ccond);//这里可以有一定策略
        pthread_mutex_unlock(&_mutex);
    }
    void pop(T* out)//输出型参数：*//输入输出型参数：&
    {
        pthread_mutex_lock(&_mutex);
        //1.判断
        while(is_empty())
        {
            pthread_cond_wait(&_ccond,&_mutex);
        }
        //2.走到这里我们保证一定不为空
        *out=_q.front();
        _q.pop();
        //3.绝对能保证队列中有空的位置
        pthread_cond_signal(&_pcond);
        pthread_mutex_unlock(&_mutex);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_pcond);
        pthread_cond_destroy(&_ccond);
        
    }
private:
    bool is_empty()
    {
        return _q.empty();
    }
    bool is_full()
    {
        return _q.size()==_maxcap;
    }
private:
    std::queue<T> _q;
    int _maxcap;//表示队列容量上限
    pthread_mutex_t _mutex;
    pthread_cond_t _pcond;//生产者对应的条件变量
    pthread_cond_t _ccond;//消费者对应的条件变量
};